
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use work.types.all;

entity sram32 is
	port (
		clk							: in    std_logic;
		reset						: in    std_logic;
		
		mem_address			: in    std_logic_vector(19 downto 0);
		mem_data_in			: in    std_logic_vector(31 downto 0);
		mem_data_out  	: out   std_logic_vector(31 downto 0);
		mem_data_size		: in    std_logic_vector(2 downto 0);
		mem_data_signed	: in    std_logic;
		mem_read				: in    std_logic;
		mem_write				: in    std_logic;
		mem_ready				: out   std_logic;

		sram_address		: out   std_logic_vector(17 downto 0);
		sram_ce1				: out   std_logic;
		sram_ub1				: out   std_logic;
		sram_lb1				: out   std_logic;
		sram_data1			: inout std_logic_vector(15 downto 0);
		sram_ce2				: out   std_logic;
		sram_ub2				: out   std_logic;
		sram_lb2				: out   std_logic;
		sram_data2			: inout std_logic_vector(15 downto 0);
		sram_oe					: out   std_logic;
		sram_we					: out   std_logic;

		overflow				: out	std_logic
	);
	
end entity;

architecture behaviour of sram32 is
	type STATE_TYPE is (RESET_STATE, IDLE, READ_WORD1B, 
		READ_WORD2A, READ_WORD2B, WRITE_WORD1, WRITE_WORD2, 
		ALIGN_OUTPUT_DATA, ALIGN_INPUT_DATA);
	signal state_i, state_o : STATE_TYPE;
	
	signal mem_address1 : std_logic_vector(17 downto 0);
	signal mem_address2 : std_logic_vector(17 downto 0);

	signal mem_data_in1, mem_data_out1_i, mem_data_out2_i, 
		mem_data_out1_o, mem_data_out2_o : std_logic_vector(31 downto 0);
	signal mem_data_in2 : std_logic_vector(31 downto 8);
		
	signal bytes_enable1_i, bytes_enable2_i, bytes_enable1_o, bytes_enable2_o, 
		bytes_enable : std_logic_vector(3 downto 0);

	component mem_decoder is
		port (
			address_offset 	: in  std_logic_vector(1 downto 0);
			mem_data_size		: in  std_logic_vector(2 downto 0);
			mem_data_signed	: in  std_logic;
			
			mem_data_in1		: in  std_logic_vector(31 downto 0);
			mem_data_in2		: in  std_logic_vector(31 downto 8);
			proc_data_in		: out std_logic_vector(31 downto 0);
			
			proc_data_out		: in  std_logic_vector(31 downto 0);
			mem_data_out1		: out std_logic_vector(31 downto 0);
			mem_data_out2		: out std_logic_vector(31 downto 0);
			
			bytes_enable1		: out std_logic_vector(3 downto 0);
			bytes_enable2		: out std_logic_vector(3 downto 0);

			overflow		: out std_logic
		);
	end component;
	
	signal store1, store2, store_addr, store_outputs : std_logic;

	signal mem_address_offset : std_logic_vector(1 downto 0);
	signal sig_overflow : std_logic;
begin
	overflow <= sig_overflow and mem_write;

	dec: mem_decoder port map(mem_address_offset, mem_data_size, mem_data_signed,
		mem_data_in1, mem_data_in2, mem_data_out, mem_data_in, 
		mem_data_out1_i, mem_data_out2_i, bytes_enable1_i, bytes_enable2_i,
		sig_overflow);

	sram_ce1 <= '0';
	sram_ce2 <= '0';
	
	sram_ub1 <= bytes_enable(3);
	sram_lb1 <= bytes_enable(2);
	sram_ub2 <= bytes_enable(1);
	sram_lb2 <= bytes_enable(0);

	process(state_o, mem_read, mem_write, bytes_enable1_o, bytes_enable2_o, 
		mem_data_out1_o, mem_data_out2_o, mem_address1, mem_address2,
		bytes_enable2_i, mem_address) begin
		
		case state_o is
			when RESET_STATE =>
				mem_ready <= '0';

				sram_data1 <= (others => '-');
				sram_data2 <= (others => '-');
				bytes_enable <= (others => '-');
				sram_address <= (others => '-');
				
				sram_we <= '1';
				sram_oe <= '1';
				
				store1 <= '0';
				store2 <= '0';
				store_addr <= '0';
				store_outputs <= '0';

				state_i <= IDLE;
			when IDLE =>
				mem_ready <= '0';

				sram_data1 <= (others => '-');
				sram_data2 <= (others => '-');
				bytes_enable <= "0000";
				sram_address <= mem_address(19 downto 2);

				sram_we <= '1';
				sram_oe <= '0';

				store1 <= '0';
				store2 <= '0';
				store_addr <= '1';
				store_outputs <= '0';
				
				if (mem_read = '1') then
					state_i <= READ_WORD1B;
				elsif (mem_write = '1') then
					-- TODO: can the compute outputs state be included in the idle state?
					state_i <= ALIGN_OUTPUT_DATA;
				else
					state_i <= IDLE;
				end if;
			-- THIS STATE IS NOW (MAY 11 2006) INCLUDED IN THE IDLE STATE
			--when READ_WORD1A =>
			--	mem_ready <= '0';

			--	sram_data1 <= (others => 'Z');
			--	sram_data2 <= (others => 'Z');
			--	bytes_enable <= "0000";
			--	sram_address <= mem_address1;

			--	sram_we <= '1';
			--	sram_oe <= '0';

			--	store1 <= '0';
			--	store2 <= '0';
			--	store_addr <= '0';
			--	store_outputs <= '0';

			--	state_i <= READ_WORD1B;
			when READ_WORD1B =>
				mem_ready <= '0';

				sram_data1 <= (others => 'Z');
				sram_data2 <= (others => 'Z');
				bytes_enable <= "0000";
				sram_address <= mem_address1;

				sram_we <= '1';
				sram_oe <= '0';

				store1 <= '1';
				store2 <= '0';
				store_addr <= '0';
				store_outputs <= '0';

				if (bytes_enable2_i = "1111") then
					state_i <= ALIGN_INPUT_DATA;
				else
					state_i <= READ_WORD2A;
				end if;
			when READ_WORD2A =>
				mem_ready <= '0';

				sram_data1 <= (others => 'Z');
				sram_data2 <= (others => 'Z');
				bytes_enable <= "0000";
				sram_address <= mem_address2;

				sram_we <= '1';
				sram_oe <= '0';

				store1 <= '0';
				store2 <= '0';
				store_addr <= '0';
				store_outputs <= '0';

				state_i <= READ_WORD2B;
			when READ_WORD2B =>
				mem_ready <= '0';

				sram_data1 <= (others => 'Z');
				sram_data2 <= (others => 'Z');
				bytes_enable <= "0000";
				sram_address <= mem_address2;

				sram_we <= '1';
				sram_oe <= '0';

				store1 <= '0';
				store2 <= '1';
				store_addr <= '0';
				store_outputs <= '0';

				state_i <= ALIGN_INPUT_DATA;
			when ALIGN_OUTPUT_DATA =>
				mem_ready <= '0';

				sram_data1 <= (others => '-');
				sram_data2 <= (others => '-');
				bytes_enable <= (others => '-');
				sram_address <= (others => '-');
				
				sram_we <= '1';
				sram_oe <= '1';
				
				store1 <= '0';
				store2 <= '0';
				store_addr <= '0';
				store_outputs <= '1';

				state_i <= WRITE_WORD1;
			when WRITE_WORD1 =>
				--mem_ready <= '0';

				sram_data1 <= mem_data_out1_o(31 downto 16);
				sram_data2 <= mem_data_out1_o(15 downto 0);
				bytes_enable <= bytes_enable1_o;
				sram_address <= mem_address1;

				sram_we <= '0';
				sram_oe <= '1';

				store1 <= '0';
				store2 <= '0';
				store_addr <= '0';
				store_outputs <= '0';

				if (bytes_enable2_i = "1111") then
					--state_i <= READY_STATE;
					state_i <= IDLE;
					mem_ready <= '1';
				else
					state_i <= WRITE_WORD2;
					mem_ready <= '0';
				end if;
			when WRITE_WORD2 =>
--				mem_ready <= '0';
				mem_ready <= '1';

				sram_data1 <= mem_data_out2_o(31 downto 16);
				sram_data2 <= mem_data_out2_o(15 downto 0);
				bytes_enable <= bytes_enable2_o;
				sram_address <= mem_address2;

				sram_we <= '0';
				sram_oe <= '1';

				store1 <= '0';
				store2 <= '0';
				store_addr <= '0';
				store_outputs <= '0';

--				state_i <= READY_STATE;
				state_i <= IDLE;
--			when READY =>
			when ALIGN_INPUT_DATA =>
				mem_ready <= '1';

				sram_we <= '1';
				sram_oe <= '1';

				sram_data1 <= (others => '-');
				sram_data2 <= (others => '-');
				bytes_enable <= (others => '-');
				sram_address <= (others => '-');

				store1 <= '0';
				store2 <= '0';
				store_addr <= '0';
				store_outputs <= '0';

				state_i <= IDLE;
		end case;
	end process;

	process(clk, reset, state_i) begin
		if (clk'event and clk = '1') then
			if (reset = '1') then
				state_o <= RESET_STATE;
			else
				state_o <= state_i;
			end if;
		end if;
	end process;

	process(clk, reset, store_addr, mem_address) begin
		if (clk'event and clk = '1') then
			if (reset = '1') then
				mem_address1 <= (others => '0');
				mem_address_offset <= (others => '0');
			elsif (store_addr = '1') then
				mem_address1 <= mem_address(19 downto 2);
				mem_address_offset <= mem_address(1 downto 0);
			end if;
		end if;
	end process;	

	process(clk, reset, mem_address1) begin
		if (clk'event and clk = '1') then
			if (reset = '1') then
				mem_address2 <= (others => '0');
			else
				mem_address2 <= mem_address1+1;
			end if;
		end if;
	end process;	

	
	process(clk, reset, store1, mem_data_in1, sram_data1, sram_data2) begin
		if (clk'event and clk = '1') then
			if (reset = '1') then
				mem_data_in1 <= (others => '0');
			elsif (store1 = '1') then
				mem_data_in1(31 downto 16) <= sram_data1;
				mem_data_in1(15 downto 0) <= sram_data2;
			end if;
		end if;
	end process;	

	process(clk, reset, store2, mem_data_in2, sram_data1, sram_data2) begin
		if (clk'event and clk = '1') then
			if (reset = '1') then
				mem_data_in2 <= (others => '0');
			elsif (store2 = '1') then
				mem_data_in2(31 downto 16) <= sram_data1;
				mem_data_in2(15 downto 8) <= sram_data2(15 downto 8);
			end if;
		end if;
	end process;	

	process(clk, reset, store_outputs, 
		mem_data_out1_i, mem_data_out2_i, bytes_enable1_i, bytes_enable2_i,
		mem_data_out1_o, mem_data_out2_o, bytes_enable1_o, bytes_enable2_o) begin
	
		if (clk'event and clk = '1') then
			if (reset = '1') then
				mem_data_out1_o <= (others => '0');
				mem_data_out2_o <= (others => '0');
				bytes_enable1_o <= (others => '0');
				bytes_enable2_o <= (others => '0');
			elsif (store_outputs = '1') then
				mem_data_out1_o <= mem_data_out1_i;
				mem_data_out2_o <= mem_data_out2_i;
				bytes_enable1_o <= bytes_enable1_i;
				bytes_enable2_o <= bytes_enable2_i;
			end if;
		end if;
	end process;	
	


end architecture;
